/**
 */
package it.rainbowbreeze.polygen.common;

import it.rainbowbreeze.libs.common.RainbowServiceLocator;
import it.rainbowbreeze.libs.logic.RainbowCrashReporter;
import it.rainbowbreeze.polygen.data.AppPreferencesDao;
import it.rainbowbreeze.polygen.data.ItemsDao;
import it.rainbowbreeze.polygen.data.webservice.RestfulClient;
import it.rainbowbreeze.polygen.data.webservice.WebserviceManager;
import it.rainbowbreeze.polygen.logic.LogicManager;
import it.rainbowbreeze.polygen.logic.MessageParser;
import it.rainbowbreeze.polygen.ui.ActivityHelper;
import android.content.Context;

import static it.rainbowbreeze.libs.common.RainbowContractHelper.checkNotNull;

/**
 * Main application classes lazy-loading singleton
 * 
 * @author Alfredo "Rainbowbreeze" Morresi
 */
public class AppEnv {
    // ------------------------------------------ Private Fields
    private static final String LOG_HASH = "AppEnv";
    private static final Object mSyncObject = new Object();

    
    // -------------------------------------------- Constructors
    private AppEnv(Context context) {
        //use default objects factory
        this(context, getDefaultObjectsFactory());
    }
    
    private AppEnv(Context context, ObjectsFactory objectsFactory) {
        //use a custom object factory
        checkNotNull(objectsFactory, "ObjectsFactory");
        setupVolatileData(context, objectsFactory);
    }

    
    // --------------------------------------- Public Properties
    /** keys for application preferences */
    public final static String APP_PREFERENCES_KEY = "PolygenPrefs";

    /** lazy loading singleton */
    public static AppEnv i(Context context) {
        synchronized (mSyncObject) {
            if (null == mInstance)
                mInstance = new AppEnv(context);
        }
        return mInstance;
    }
    /** lazy loading singleton, reload the environment each time (for testing purposes) */
    public static AppEnv i(Context context, ObjectsFactory objectsFactory) {
        synchronized (mSyncObject) {
            if (null == mInstance) {
                mInstance = new AppEnv(context, objectsFactory);
            } else {
                //force the rebuild of all the environment
                mInstance.setupVolatileData(context, objectsFactory);
            }
        }
        return mInstance;
    }
    private static AppEnv mInstance;

    
    /** Application version displayed to the user (about activity etc) */
    public final static String APP_DISPLAY_VERSION = "1.0";
    
    /** Application name used during the ping of update site */
    public final static String APP_INTERNAL_NAME = "PolygenDroid";

    /** Application version for internal use (update, crash report etc) */
    public final static String APP_INTERNAL_VERSION = "00.01.00";

    /** Application version for internal use (update, crash report etc) */
    public final static String EMAIL_FOR_ERROR_LOG = "devel@rainbowbreeze.it";
    
    /** Tag to use in the log */
    public final static String LOG_TAG = "PolygenDroid";
    
    /** Not found item in content provider */
    public static final long NOT_FOUND = -1;

    /** url where send statistics about application */
    public static final String STATISTICS_WEBSERVER_URL = "http://www.rainbowbreeze.it/devel/getlatestversion.php";

    /** Default objects factory, testing purposes */
    protected static final ObjectsFactory defaultObjectsFactory = new ObjectsFactory();
    public static final ObjectsFactory getDefaultObjectsFactory()
    { return defaultObjectsFactory; }

    /** Base address for polygen webservice */
//    public static final String BASE_THOTPOT_URL = "http://thotpotgae.appspot.com/";
//    public static final String BASE_THOTPOT_URL = "http://webapp-test.thotpot.com/";
    public static final String BASE_SERVER_URL = "http://mobileapp-test.thotpot.com/";
    
    
    // ------------------------------------------ Public Methods

    public LogFacility getLogFacility() {
        return checkNotNull(RainbowServiceLocator.get(
                LogFacility.class), LogFacility.class.getSimpleName());
    }
    
    public AppPreferencesDao getAppPreferencesDao() {
        return checkNotNull(RainbowServiceLocator.get(
                AppPreferencesDao.class), AppPreferencesDao.class.getSimpleName());
    }
    
    public ActivityHelper getActivityHelper() {
        return checkNotNull(RainbowServiceLocator.get(
                ActivityHelper.class), ActivityHelper.class.getSimpleName());
    }
    
    public LogicManager getLogicManager() {
        return checkNotNull(RainbowServiceLocator.get(
                LogicManager.class), LogicManager.class.getSimpleName());
    }
    
    public WebserviceManager getWebserviceManager() {
        return checkNotNull(RainbowServiceLocator.get(
                WebserviceManager.class), WebserviceManager.class.getSimpleName());
    }
    
    public MessageParser getMessageParser() {
        return checkNotNull(RainbowServiceLocator.get(
                MessageParser.class), MessageParser.class.getSimpleName());
    }
    
    public ItemsDao getItemsDao() {
        return checkNotNull(RainbowServiceLocator.get(
                ItemsDao.class), ItemsDao.class.getSimpleName());
    }
    
    
    // ----------------------------------------- Private Methods
    /**
     * Setup the volatile data of application.
     * This is needed because sometime the system release memory
     * without completely close the application, so all static fields
     * will become null :(
     * 
     */
    private void setupVolatileData(Context context, ObjectsFactory mObjectsFactory) {
        //set the log tag
        LogFacility logFacility = mObjectsFactory.createLogFacility(LOG_TAG);
        logFacility.i(LOG_HASH, "Initializing environment");

        //empty service locator
        RainbowServiceLocator.clear();
        //put log facility
        RainbowServiceLocator.put(logFacility);

        //initialize (and automatically register) crash reporter
        RainbowCrashReporter crashReport = mObjectsFactory.createCrashReporter(context);
        RainbowServiceLocator.put(crashReport);
        //create services and helper respecting IoC dependencies
//        ActivityHelper activityHelper = mObjectsFactory.createActivityHelper(context, logFacility);
//        RainbowServiceLocator.put(activityHelper);
        AppPreferencesDao appPreferencesDao = mObjectsFactory.createAppPreferencesDao(context, APP_PREFERENCES_KEY);
        RainbowServiceLocator.put(appPreferencesDao);
        ActivityHelper activityHelper = mObjectsFactory.createActivityHelper(logFacility, context);
        RainbowServiceLocator.put(activityHelper);
        RestfulClient restfulClient = mObjectsFactory.createRestfulClient(logFacility);
        RainbowServiceLocator.put(restfulClient);
        ItemsDao itemsDao = mObjectsFactory.createItemsDao(logFacility);
        RainbowServiceLocator.put(itemsDao);
        WebserviceManager webserviceManager = mObjectsFactory.createWebserviceManager
                (logFacility, restfulClient);
        RainbowServiceLocator.put(webserviceManager);
        LogicManager logicManager = mObjectsFactory.createLogicManager(
                logFacility,
                appPreferencesDao,
                AppEnv.APP_INTERNAL_VERSION);
        RainbowServiceLocator.put(logicManager);
        
        MessageParser messageParser = mObjectsFactory.createMessageParser(logFacility);
        RainbowServiceLocator.put(messageParser);
    }
    
    
    // ----------------------------------------- Private Classes
    public static class ObjectsFactory {
        public LogFacility createLogFacility(String logTag)
        { return new LogFacility(logTag); }
        
        public MessageParser createMessageParser(LogFacility logFacility) {
            return new MessageParser(logFacility);
        }

        public RainbowCrashReporter createCrashReporter(Context context)
        { return new RainbowCrashReporter(context); }
        
//        public ActivityHelper createActivityHelper(Context context, LogFacility logFacility)
//        { return new ActivityHelper(logFacility, context); }
//        
        public AppPreferencesDao createAppPreferencesDao(Context context, String appPreferencesKey)
        { return new AppPreferencesDao(context, appPreferencesKey); }
        
        public ActivityHelper createActivityHelper(LogFacility logFacility, Context context)
        { return new ActivityHelper(logFacility, context); }
        
        public RestfulClient createRestfulClient(LogFacility logFacility)
        { return new RestfulClient(logFacility); }
        
        public ItemsDao createItemsDao(LogFacility logFacility)
        { return new ItemsDao(logFacility); }
        
        public WebserviceManager createWebserviceManager(
                LogFacility logFacility,
                RestfulClient restfulClient)
        { return new WebserviceManager(logFacility, restfulClient); }
        
        public LogicManager createLogicManager(
                LogFacility logFacility,
                AppPreferencesDao appPreferencesDao,
                String currentAppVersion) {
            return new LogicManager(
                logFacility,
                appPreferencesDao,
                currentAppVersion);
        }
        
    }


}
